/*
* Copyright (C) 2010, Jared Jennings <jaredljennings@gmail.com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Diagnostics;
using Gtk;
namespace org.jaredjennings.mysshmenu
{
	public class TreeViewExample
	{
		public static void Main ()
		{
			Gtk.Application.Init ();
			//new TreeViewExample ();
			new mysshmenuWindow ();
			Gtk.Application.Run ();
			
		}
	}
	
	public class mysshmenuWindow : Gtk.TreeView
	{
		StoreBackend sb = StoreBackend.GetInstance ();
		//** Gtk.Entry filterEntry;
		//** Gtk.TreeModelFilter filter;
		Gtk.ListStore musicListStore;
		Gtk.Window window;
		HostObj _selected_host;

		public mysshmenuWindow ()
		{
			// Create a Window
			window = new Gtk.Window ("mySSHMenu");
			
			Gtk.Button moreServers = new Gtk.Button ("Add Server");
			moreServers.Name = "Add More Servers";
			moreServers.TooltipText = "You can add more servers to the list";
			
			
			Gtk.Button exitProg = new Gtk.Button ("Exit");
			exitProg.Name = "Exit Program";
			
			exitProg.Clicked += new EventHandler (onClicked_closeProg);
			moreServers.Clicked += new EventHandler (Onclicked_moreServers);
			
			window.SetSizeRequest (500, 200);
			
			// Create an Entry used to filter the tree
			//** filterEntry = new Gtk.Entry ();
			
			// Fire off an event when the text in the Entry changes
			//** filterEntry.Changed += OnFilterEntryTextChanged;
			
			// Create a nice label describing the Entry
			//** Gtk.Label filterLabel = new Gtk.Label ("Add More Servers:");
			
			// Put them both into a little box so they show up side by side
			Gtk.HBox filterBox = new Gtk.HBox ();
			filterBox.PackStart (exitProg, false, false, 5);
			filterBox.PackStart (moreServers, false, false, 5);
			
			// Create our TreeView
			//Gtk.TreeView tree = new Gtk.TreeView ();
			
			// Create a box to hold the Entry and Tree
			Gtk.VBox box = new Gtk.VBox ();
			
			// Add the widgets to the box
			box.PackStart (filterBox, false, false, 5);
			box.PackStart (this, true, true, 5);
			
			window.Add (box);
			
			// Create a column for the artist name
			Gtk.TreeViewColumn nameColumn = new Gtk.TreeViewColumn ();
			nameColumn.Title = "Server name";
			
			// Create the text cell that will display the artist name
			Gtk.CellRendererText serverNameCell = new Gtk.CellRendererText ();
			
			// Add the cell to the column
			nameColumn.PackStart (serverNameCell, true);
			
			// Create a column for the song title
			Gtk.TreeViewColumn addrColumn = new Gtk.TreeViewColumn ();
			addrColumn.Title = "Address";
			
			// Do the same for the song title column
			Gtk.CellRendererText serverAddrCell = new Gtk.CellRendererText ();
			addrColumn.PackStart (serverAddrCell, true);
			
			// Add the columns to the TreeView
			this.AppendColumn (nameColumn);
			this.AppendColumn (addrColumn);
			
			// Tell the Cell Renderers which items in the model to display *** Using MVC
			//nameColumn.AddAttribute (serverNameCell, "text", 0);
			//songColumn.AddAttribute (serverAddrCell, "text", 1);
			
			nameColumn.SetCellDataFunc (serverNameCell, new Gtk.TreeCellDataFunc (RenderServerName));
			addrColumn.SetCellDataFunc (serverAddrCell, new Gtk.TreeCellDataFunc (RenderServerAddr));
			
			// Create a model that will hold two strings - Artist Name and Song Title
			// ** Gtk.ListStore musicListStore = new Gtk.ListStore (typeof (string), typeof (string));
			
			// Add some data to the store
			musicListStore = sb.getListValues ();
			
			// Instead of assigning the ListStore model directly to the TreeStore, we create a TreeModelFilter
			// which sits between the Model (the ListStore) and the View (the TreeView) filtering what the model sees.
			// Some may say that this is a "Controller", even though the name and usage suggests that it is still part of
			// the Model.
			//**filter = new Gtk.TreeModelFilter (musicListStore, null);
			
			this.Model = musicListStore;
			
			// Specify the function that determines which rows to filter out and which ones to display
			//*filter.VisibleFunc = new Gtk.TreeModelFilterVisibleFunc (FilterTree);
			
			// Assign the filter as our tree's model
			//*tree.Model = filter;
			this.RowActivated += tree_CursorChanged;
			//this.ButtonPressEvent += new ButtonPressEventHandler (OnSelectionChanged);
			
			
			// Show the window and everything on it
			window.ShowAll ();
		}

		/// <summary>
		/// Provides a method to render the Host Object into string values
		/// </summary>
		/// <param name="column">
		/// A <see cref="Gtk.TreeViewColumn"/>
		/// </param>
		/// <param name="cell">
		/// A <see cref="Gtk.CellRenderer"/>
		/// </param>
		/// <param name="model">
		/// A <see cref="Gtk.TreeModel"/>
		/// </param>
		/// <param name="iter">
		/// A <see cref="Gtk.TreeIter"/>
		/// </param>
		private void RenderServerName (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			HostObj host = (HostObj) model.GetValue (iter, 0);
			(cell as Gtk.CellRendererText).Text = host.NAME;
		}
		
		/// <summary>
		/// Provides a method to render the Host Object into string values
		/// </summary>
		/// <param name="column">
		/// A <see cref="Gtk.TreeViewColumn"/>
		/// </param>
		/// <param name="cell">
		/// A <see cref="Gtk.CellRenderer"/>
		/// </param>
		/// <param name="model">
		/// A <see cref="Gtk.TreeModel"/>
		/// </param>
		/// <param name="iter">
		/// A <see cref="Gtk.TreeIter"/>
		/// </param>
		private void RenderServerAddr (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			HostObj host = (HostObj) model.GetValue (iter, 0);
			(cell as Gtk.CellRendererText).Text = host.ADDRESS;
		}		
		
        /// <summary>
        /// The TreeView has a built in function which is called upon a OnButtonPressEvent
        /// We override the function to capture clicks. We then check to see if it was a right click (3)
        /// Posted by Jacob Emcken http://www.emcken.dk/weblog/archives/179-mono-coding-capturing-right-clicks-in-a-gtktreeview.html
        /// </summary>
        /// <param name="evnt">
        /// A <see cref="Gdk.EventButton"/>
        /// </param>
        /// <returns>
        /// A <see cref="System.Boolean"/>
        /// </returns>
        protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
        {
			if(evnt.Button == 3) {
						TreeModel model;
						TreeIter iter;
						if (this.Selection.GetSelected (out model, out iter)) {
					HostObj host = getHostFromModel(iter, model);
							Logger.Debug ("Selected row during right click" + host.NAME);
					
							loadMenuProperties(model, iter, 0);
						}				
                        return true;
                }
                return base.OnButtonPressEvent(evnt);
        }
		/// <summary>
		/// Abstracts a HostObj from TreeModel instance
		/// </summary>
		/// <param name="model">
		/// A <see cref="TreeModel"/>
		/// </param>
		/// <returns>
		/// A <see cref="HostObj"/>
		/// </returns>
		private HostObj getHostFromModel(TreeIter iter, TreeModel model) {
			HostObj host = model.GetValue(iter, 0) as HostObj;
			return host;
		}
		
		/// <summary>
		/// Load a menu to edit host object options
		/// </summary>
		private void loadMenuProperties(TreeModel selected_model, TreeIter iter, int icolm) {
	        Gtk.Menu jBox = new Gtk.Menu();
	        Gtk.MenuItem MenuItem1 = new MenuItem("Edit");
			_selected_host = getHostFromModel(iter, selected_model);
			MenuItem1.Activated += delegate(object sender, EventArgs e) {
				//HostObj host = getHostFromModel(iter, selected_model);
			     Logger.Debug ("edit selected " + _selected_host.NAME);
				openEditServerProps(_selected_host);
			};
	        
			jBox.Add(MenuItem1);       
			
	        Gtk.MenuItem MenuItem2 = new MenuItem("Delete");			
			MenuItem2.Activated += delegate(object sender, EventArgs EventArgs) { /* load dialog delete server yes /no */

				Gtk.Dialog delDialog = new Gtk.Dialog(
				                                      "Delete Server", 
				                                      window,
				                                      Gtk.DialogFlags.DestroyWithParent);
				delDialog.Modal = true;
				delDialog.AddButton ("YES", ResponseType.Yes);
				delDialog.AddButton ("NO", ResponseType.No);
				delDialog.Response += on_deldialog_response;

				delDialog.Run();
				delDialog.Destroy();
			};
			
	        jBox.Append(MenuItem2);        
	        jBox.ShowAll();
	        jBox.Popup();
		}
		
		void on_deldialog_response (object obj, ResponseArgs args)
        {
            Logger.Debug (args.ResponseId.ToString());
			if (args.ResponseId == ResponseType.Yes) {
				Logger.Debug ("Deleting host :" +_selected_host.NAME);
				sb.delete(_selected_host);
			}
			else
				Logger.Debug ("Do no delete host");
        }

		
//		protected virtual void OnSelectionChanged (object sender, EventArgs e) {
//			Logger.Debug ("OnSelectionChanged");
//			
//			
//			TreeModel model;
//			TreeIter iter;
//			Logger.Debug ("EventArgs:" + this.Selection.GetSelected(out iter));
//			if (this.Selection.GetSelected (out model, out iter)) {
//				Logger.Debug ("Selected row on right click" + model.GetValue (iter, 0).ToString ());
//			}
//		}

		private void onClicked_closeProg (object sender, EventArgs e)
		{
			Logger.Debug ("Closing application");
			Application.Quit ();
		}
		
		private void Onclicked_moreServers (object sender, EventArgs e)
		{
			Logger.Debug ("Loading Window to add more servers");
			AddServer addServWin = new AddServer ();
			addServWin.ShowAll ();
		}
			
		/// <summary>
		/// Item in the tree list was double-clicked (selected)
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="EventArgs"/>
		/// </param>
		void tree_CursorChanged (object sender, EventArgs e)
		{
			TreeSelection selection = (sender as TreeView).Selection;
			TreeModel model;
			TreeIter iter;
			
			// THE ITER WILL POINT TO THE SELECTED ROW
			if (selection.GetSelected (out model, out iter)) {
				HostObj host = getHostFromModel(iter, model); /* get the selected value from the list store */
				Logger.Debug ("Selected Value:" + host.NAME + " - " + host.ADDRESS);
				
				if (host.CONNTYPE.Equals (ConnectionType.RDP))
					RemoteConnCmd.GetInstance ().launchRemoteConnection (host);
				
			}
		}

		/// <summary>
		/// Possibly filter saved configurations if there are a lot.
		/// </summary>
		/// <param name="model">
		/// A <see cref="Gtk.TreeModel"/>
		/// </param>
		/// <param name="iter">
		/// A <see cref="Gtk.TreeIter"/>
		/// </param>
		/// <returns>
		/// A <see cref="System.Boolean"/>
		/// </returns>
//		private bool FilterTree (Gtk.TreeModel model, Gtk.TreeIter iter)		/* currently not being used */
//		{
//			string artistName = model.GetValue (iter, 0).ToString ();
//			
//			if (filterEntry.Text == "")
//				return true;
//			
//			if (artistName.IndexOf (filterEntry.Text) > -1)
//				return true;
//			else
//				return false;
//		}
		/// <summary>
		/// Part of FilterTree if we want to implement a filter system because so many server configurations
		/// are saved.
		/// </summary>
		/// <param name="o">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="args">
		/// A <see cref="System.EventArgs"/>
		/// </param>
//		 private void OnFilterEntryTextChanged (object o, System.EventArgs args)		/* currently not being used */
//		{
//			filter.Refilter (); // Since the filter text changed, tell the filter to re-determine which rows to display
//		} 
		
		/// <summary>
		/// Allows us to edit a hosts properties. Like address, connection ports, etc.
		/// </summary>
		/// <param name="host">
		/// A <see cref="HostObj"/>
		/// </param>
		private void openEditServerProps(HostObj host) {
			EditServerProps srvprops = new EditServerProps(host);
			srvprops.ShowAll();
		}
	}
}
